package lock.deadlock;

import java.math.BigDecimal;

/**
 * 转账
 * 通过hash算法进行优化
 *
 * @author 86155
 * @date 2025/08/16
 */
public class TransferMoney {

    /**
     * hash 冲突时使用第三个锁(优秀的hash算法冲突是很少的！)
     */
    private static final Object conflictShareLock = new Object();

    /**
     * 转账
     *
     * @param accountFrom 帐户来自
     * @param accountTo   帐户至
     * @param mat         转移钱数
     */
    public static void transferMoney(Account accountFrom,
                                     Account accountTo,
                                     BigDecimal mat) throws Exception {
        int accountFromHash = System.identityHashCode(accountFrom);
        int accountToHash = System.identityHashCode(accountTo);
        //通过hash来保证获取锁顺序一致
        if (accountFromHash > accountToHash) {
            synchronized (accountFrom) {
                synchronized (accountTo) {
                    transferMoneyHandler(accountFrom, accountTo, mat);
                }
            }
        } else if (accountFromHash < accountToHash) {
            synchronized (accountTo) {
                synchronized (accountFrom) {
                    transferMoneyHandler(accountFrom, accountTo, mat);
                }
            }
        } else {
            //相同情况
            synchronized (conflictShareLock) {
                synchronized (accountFrom) {
                    synchronized (accountTo) {
                        transferMoneyHandler(accountFrom, accountTo, mat);
                    }
                }
            }
        }
    }


    private static void transferMoneyHandler(Account accountFrom,
                                            Account accountTo,
                                            BigDecimal mat) throws Exception {
        BigDecimal fromBalance = accountFrom.getBalance();
        if (fromBalance.compareTo(mat) < 0) {
            throw new Exception(accountFrom + " is less than mat");
        } else {
            accountFrom.setBalance(accountFrom.getBalance().subtract(mat));
            accountTo.setBalance(accountTo.getBalance().add(mat));
            System.out.println("Form" + accountFrom.getAccountName() + ": "
                    + accountFrom.getBalance().toPlainString()
                    + "\t" + "To" + accountTo.getAccountName() + ": "
                    + accountTo.getBalance().toPlainString());
        }
    }
    /*public static void transferMoney(Account accountFrom,
                                     Account accountTo,
                                     BigDecimal mat) throws Exception {
                                     //存在死锁风险
        synchronized (accountFrom) {
            synchronized (accountTo) {
                //开始转账 ,计算要转出账户的余额
                BigDecimal fromBalance = accountFrom.getBalance();
                if (fromBalance.compareTo(mat) < 0) {
                    throw new Exception(accountFrom + " is less than mat");
                } else {
                    accountFrom.setBalance(fromBalance.subtract(mat));
                    accountTo.setBalance(fromBalance.add(mat));
                    System.out.println("Form" + accountFrom.getAccountName() + ": "
                            + accountFrom.getBalance().toPlainString()
                            +"\t" + "To" +  accountTo.getAccountName() + ": "
                            + accountTo.getBalance().toPlainString());
                }

            }
        }
    }*/
}
